<?php
/*
	* 类与对象 构造函数和析构函数
	* https://www.php.net/manual/zh/language.oop5.decon.php
	* Adair  zouhdai@gmail.com
	* 2021-08-17
*/

class Product {

    private  $id;
    private  $name;

    private function __construct(?int $id = null, ?string $name = null) {
        $this->id = $id." abc";
        $this->name = $name." abc";
    }

    public static function fromBasicData(int $id, string $name) {
        $new = new static($id, $name);
        return $new;
    }

    public static function fromJson(string $json) {
        $data = json_decode($json, true);
        var_dump($data);
        return new static($data['id'], $data['name']);
    }

    public static function fromXml(string $xml) {
        // 此处放置自己的代码逻辑
        //var_dump($xml);
        //$data = convert_xml_to_array($xml);
        $data= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        //var_dump($data);
        $new = new static();
        $new->id = $data['id'];
        $new->name = $data['name'];
        return $new;
    }
}

$p1 = Product::fromBasicData(5, 'Widget');
$some_json_string =  '{"id":1,"name":2}';
$some_xml_string = "<xml><id>1</id><name>John</name></xml>";
$p2 = Product::fromJson($some_json_string);
$p3 = Product::fromXml($some_xml_string);

var_dump($p1,$p2,$p3);



class Father {

    public function getNewFather() {
        return new self();
    }

    public function getNewCaller() {
        return new static();
    }

}

$f = new Father();

print get_class($f->getNewFather()).'<br>';
print get_class($f->getNewCaller()).'<br>';




class Sun1 extends Father {

}

class Sun2 extends Father {

}

$sun1 = new Sun1();
$sun2 = new Sun2();

print get_class($sun1->getNewFather()).'<br>';
print get_class($sun1->getNewCaller()).'<br>';
print get_class($sun2->getNewFather()).'<br>';
print get_class($sun2->getNewCaller()).'<br>';

/*首先，他们的区别只有在继承中才能体现出来，如果没有任何继承，那么这两者是没有区别的。

然后，new self()返回的实例是万年不变的，无论谁去调用，都返回同一个类的实例，而new static()则是由调用者决定的。

上面的$sun1->getNewCaller()的调用者是$sun1对吧！$sun1是类Sun1的实例，所以返回的是Sun1这个类的实例，$sun2同样的道理就不赘述了。*/



class MyDestructableClass 
{
    function __construct() {
        print "In constructor\n<br>";
    }

    function __destruct() {
        print "Destroying abc-- " . __CLASS__ . "\n<br>";
    }
}

$obj = new MyDestructableClass();







//header("Content-type: text/plain");

class Foo {
   
    /**
     * An indentifier
     * @var string
     */
    private $name;
    /**
     * A reference to another Foo object
     * @var Foo
     */
    private $link;

    public function __construct($name) {
        $this->name = $name;
    }

    public function setLink(Foo $link){
        $this->link = $link;
    }

    public function __destruct() {
        echo 'Destroying: ', $this->name, PHP_EOL. "\n<br>";
    }
}

// create two Foo objects:
$foo = new Foo('Foo 1');
$bar = new Foo('Foo 2');

// make them point to each other
$foo->setLink($bar);
$bar->setLink($foo);

// destroy the global references to them
$foo = null;
$bar = null;

// we now have no way to access Foo 1 or Foo 2, so they OUGHT to be __destruct()ed
// but they are not, so we get a memory leak as they are still in memory.
//
// Uncomment the next line to see the difference when explicitly calling the GC:
// gc_collect_cycles();
//
// see also: http://www.php.net/manual/en/features.gc.php
//

// create two more Foo objects, but DO NOT set their internal Foo references
// so nothing except the vars $foo and $bar point to them:
$foo = new Foo('Foo 3');
$bar = new Foo('Foo 4');

// destroy the global references to them
$foo = null;
$bar = null;

// we now have no way to access Foo 3 or Foo 4 and as there are no more references
// to them anywhere, their __destruct() methods are automatically called here,
// BEFORE the next line is executed:

echo 'End of script', PHP_EOL. "\n<br>";









class A {
    protected $id;

    public function __construct($id)
    {
        $this->id = $id;
        echo "construct {$this->id}\n<br>";
    }

    public function __destruct()
    {
        echo "destruct {$this->id}\n<br>";
    }
}

$a = new A(1);
echo "-------------\n<br>";
$aa = new A(2);
echo "=============\n<br>";













class Mobile {

    /**
     * Some device properties
     *
     * @var string
     * @access public
     */
    public $deviceName,$deviceVersion,$deviceColor;
   
    /**
     * Set some values for Mobile::properties
     *
     * @param string device name
     * @param string device version
     * @param string device color
     */
    public function __construct ($name,$version,$color) {
        $this->deviceName = $name;
        $this->deviceVersion = $version;
        $this->deviceColor = $color;
        echo "The ".__CLASS__." class is stratup.<br /><br />";
    }
   
    /**
     * Some Output
     *
     * @access public
     */
    public function printOut () {
        echo 'I have a '.$this->deviceName
            .' version '.$this->deviceVersion
            .' my device color is : '.$this->deviceColor."<br />";
    }
   
    /**
     * Umm only for example we will remove Mobile::$deviceName Hum not unset only to check how __destruct working
     *
     * @access public
     */
    public function __destruct () {
        $this->deviceName = 'Removed';
        echo '<br /><br />Dumpping Mobile::deviceName to make sure its removed, Olay :';
        var_dump($this->deviceName);
        echo "<br />The ".__CLASS__." class is shutdown.<br />";
    }

}

// Oh ya instance
$mob = new Mobile('iPhone','5','Black');

// print output
$mob->printOut();






/*error_reporting(0);


class Logger
{
    protected $rows = array();

    public function __construct()
    {
        register_shutdown_function(array($this, '__destruct'));
    }

    public function __destruct()
    {
    	$this->rows[] = error_get_last();
        $this->save();
    }

    public function log($row)
    {
        $this->rows[] = $row;
    }

    public function save()
    {
    	//var_dump($this->rows);
        echo '<ul>';
        foreach ($this->rows as $row)
        {
        	if(is_array($row)){
        		 echo '<ul>';
        		 foreach ($row as $row_1){
        		 	echo '<li>', $row_1, '</li>';
        		 }
        		 echo '</ul>';
        	}else{
        		echo '<li>', $row, '</li>';
        	}
            
        }
        //echo '<li>', error_get_last(), '</li>';
        echo '</ul>';
    }
}

$logger = new Logger;
$logger->log('Before');

$nonset->foo();

$logger->log('After');*/



